﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RenderEngine;
using IndicoRender;
using RenderEngineInterfaces;
using IndicoInterface.SimpleAgendaDataModel;
using System.Threading.Tasks;
using DeepZoomPivotConstructor.VisualLib;
using System.ComponentModel.Composition;
using System.Drawing;
using DeepZoomPivotConstructor.VisualLib.Hotspots;

namespace t_IndicoRender
{
    /// <summary>
    /// Test the rendering for a single talk
    /// </summary>
    [TestClass]
    public class t_RenderIndicoTalk
    {
        public t_RenderIndicoTalk()
        {
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }
        [TestInitialize]
        public void InitForTest()
        {
            t_TestingLibrary.Utilities.MyClassInit();
            t_TestingLibrary.Utilities.AddPart(new RenderControl());
            t_TestingLibrary.Utilities.AddPart(new LayoutHelper());
        }

        [Import]
        private IRenderEngine MyRender { get; set; }

        [TestCleanup]
        public void ShutDownTest()
        {
            t_TestingLibrary.Utilities.MyClassDone();
        }

        [TestMethod]
        public void TestCreateTalk()
        {
            RenderIndicoTalk t = new RenderIndicoTalk();
        }

        [TestMethod]
        public void TestCanRender()
        {
            RenderIndicoTalk t = new RenderIndicoTalk();
            Talk tlk = CreateSimpleTalk();
            Assert.AreEqual(RenderPluginPriority.RPPGeneric, t.RenderPriority(tlk), "Expected to be able to render this dude");
        }

        private static Talk CreateSimpleTalk()
        {
            Talk tlk = new Talk()
            {
                Title = "Talk title",
                ID = "5",
                StartDate = DateTime.Now,
                EndDate = DateTime.Now,
                SlideURL = "http://www.nytimes.com",
                Speakers = new string[] { "G-Man" }
            };
            return tlk;
        }

        [TestMethod]
        public void TestNullRender()
        {
            t_TestingLibrary.Utilities.AddPart(this);
            RenderIndicoTalk tr = new RenderIndicoTalk();
            t_TestingLibrary.Utilities.Compose(tr);

            var result = tr.Render((Talk)null);
            Assert.IsNotNull(result, "Future should not have been null!");
            Assert.IsNull(result.Result, "Expect the returned value to be null!");
        }

        [Export(typeof(IRenderItem))]
        [RenderInfo(typeof(Uri))]
        class RenderAUri : IRenderItem, IRenderableObjectCompare
        {
            public double XWidth = 1.0;
            public double XHeight = 2.0;
            public List<string> StringsToFailOne = new List<string>();

            public Task<Visual> Render(object what)
            {
                return Task<Visual>.Factory.StartNew(() =>
                    {
                        if (StringsToFailOne.Contains((what as Uri).OriginalString))
                        {
                            return null;
                        }
                        else
                        {
                            var bt = new VisualBitmapImage(XWidth, XHeight, 100, Color.Black);
                            return bt;
                        }
                    });
            }

            public RenderPluginPriority RenderPriority(object what)
            {
                return RenderPluginPriority.RPPGeneric;
            }

            public long GetObjectHash(object what)
            {
                return (what as Uri).AbsolutePath.GetHashCode();
            }

            public bool ObjectsEqual(object o1, object o2)
            {
                return ((o1 as Uri).OriginalString == (o2 as Uri).OriginalString);
            }

            public bool IsOutOfDate(object what, object metaData)
            {
                return false;
            }

            public object GetObjectDateMetaData(object what)
            {
                return 12345;
            }
        }

        [TestMethod]
        public void TestRenderNormalTalk()
        {
            RenderIndicoTalk tr = new RenderIndicoTalk();
            t_TestingLibrary.Utilities.AddPart(new RenderAUri());
            t_TestingLibrary.Utilities.AddPart(this);
            t_TestingLibrary.Utilities.Compose(tr);

            Talk tlk = CreateSimpleTalk();
            var result = tr.Render(tlk);
            Assert.IsNotNull(result, "Expected a decent future!");
            Assert.IsNotNull(result.Result, "Expected a non-null visual resutl!");
            Visual v = result.Result;
            Assert.AreEqual(1, v.SGNodeList.Count, "Expecting only a single guy to come back from rendering a single talk");
            Assert.IsTrue(v.Width < 11.0, "Width is too big!");
            Assert.IsNotNull(v.Info, "Expecting meta-data!");
            Assert.AreEqual(tlk.Title, v.Info.Title, "Title didn't make it back ok!");
            Assert.AreEqual(1, v.Info.Info.Length, "Expected one line of extra text!");
        }

        [TestMethod]
        public void TestRenderMaterialTalk()
        {
            RenderIndicoTalk tr = new RenderIndicoTalk();
            t_TestingLibrary.Utilities.AddPart(new RenderAUri());
            t_TestingLibrary.Utilities.AddPart(this);
            t_TestingLibrary.Utilities.Compose(tr);

            Talk tlk = CreateSimpleTalk();
            tlk.TalkType = TypeOfTalk.ExtraMaterial;

            var result = tr.Render(tlk);
            Assert.IsNotNull(result, "Expected a decent future!");
            Assert.IsNotNull(result.Result, "Expected a non-null visual resutl!");
            Visual v = result.Result;
            Assert.AreEqual(1, v.SGNodeList.Count, "Expecting only a single guy to come back from rendering a single talk");
            Assert.IsTrue(v.Width < 11.0, "Width is too big!");
            Assert.IsNotNull(v.Info, "Expecting meta-data!");
            Assert.AreEqual(tlk.Title, v.Info.Title, "Title didn't make it back ok!");
            Assert.AreEqual(1, v.Info.Info.Length, "Expected one line of extra text!");
            Assert.AreEqual("Extra Material", v.Info.Info[0], "expected a simple notation");
        }

        [TestMethod]
        public void TestRenderOnlySubtalks()
        {
            RenderIndicoTalk tr = new RenderIndicoTalk();
            t_TestingLibrary.Utilities.AddPart(new RenderAUri());
            t_TestingLibrary.Utilities.AddPart(this);
            t_TestingLibrary.Utilities.Compose(tr);

            Talk t = CreateNullTalkWithSubTalks();

            var result = tr.Render(t);
            Assert.IsNotNull(result, "expected valid future!");
            Assert.IsNotNull(result.Result, "Expected a non-zero visual result!");

            Visual v = result.Result;
            Assert.AreEqual(4, v.SGNodeList.Count, "Expected a slide + title back for both talks");
        }

        [TestMethod]
        public void TestRenderSubTalksWithNullST()
        {
            RenderIndicoTalk tr = new RenderIndicoTalk();
            t_TestingLibrary.Utilities.AddPart(new RenderAUri());
            t_TestingLibrary.Utilities.AddPart(this);
            t_TestingLibrary.Utilities.Compose(tr);

            Talk t = CreateNullTalkWithSubTalks();

            t.SubTalks[1].SlideURL = null;

            var result = tr.Render(t);
            Assert.IsNotNull(result, "expected valid future!");
            Assert.IsNotNull(result.Result, "Expected a non-zero visual result!");

            Visual v = result.Result;
            Assert.AreEqual(2, v.SGNodeList.Count, "Expected a slide + title back for both talks");
        }

        [TestMethod]
        public void TestSubTalkHotspotLinks()
        {
            RenderIndicoTalk tr = new RenderIndicoTalk();
            t_TestingLibrary.Utilities.AddPart(new RenderAUri());
            t_TestingLibrary.Utilities.AddPart(this);
            t_TestingLibrary.Utilities.Compose(tr);

            Talk t = CreateNullTalkWithSubTalks();

            var result = tr.Render(t);
            var HS = from v in result.Result.GetHierarchicalEnumerator(v => false)
                     let vhs = v as VisualHotSpot
                     where vhs != null
                     select vhs;

            List<HSActionLink> links = new List<HSActionLink>();
            foreach (var item in HS)
            {
                item.GetAllActoinData(a => {
                    HSActionLink l = a as HSActionLink;
                    if (l != null) {
                        links.Add(l);
                    }
                });
            }
            Assert.AreEqual(2, links.Count(), "Didn't find expected number of hot spot links!");
        }

        [TestMethod]
        public void TestCanRenderSubTalkOnly()
        {
            RenderIndicoTalk r = new RenderIndicoTalk();
            Talk t = CreateNullTalkWithSubTalks();
            Assert.AreEqual(RenderPluginPriority.RPPGeneric, r.RenderPriority(t), "Expected generic render propbability for sub talk with no slide url!");
        }

        /// <summary>
        /// Creates a talk with 2 sub talks. The parent URL is null.
        /// </summary>
        /// <returns></returns>
        private static Talk CreateNullTalkWithSubTalks()
        {
            Talk t = CreateSimpleTalk();
            string tempUrl = t.SlideURL;
            t.SlideURL = null;

            Talk st1 = new Talk();
            st1.Title = "Sub Talk #1";
            st1.ID = "55";
            st1.SlideURL = tempUrl;

            Talk st2 = new Talk();
            st2.Title = "Sub Talk #2";
            st2.ID = "56";
            st2.SlideURL = tempUrl;

            t.SubTalks = new Talk[] { st1, st2 };
            return t;
        }

        [TestMethod]
        public void TestRenderBigTalk()
        {
            RenderIndicoTalk tr = new RenderIndicoTalk();
            RenderAUri ruri = new RenderAUri()
            {
                XHeight = 20.0,
                XWidth = 30.0
            };

            t_TestingLibrary.Utilities.AddPart(ruri);
            t_TestingLibrary.Utilities.AddPart(this);
            t_TestingLibrary.Utilities.Compose(tr);

            Talk tlk = CreateSimpleTalk();
            var result = tr.Render(tlk);
            Assert.IsNotNull(result, "Expected a decent future!");
            Assert.IsNotNull(result.Result, "Expected a non-null visual resutl!");
            Visual v = result.Result;
            Assert.IsTrue(v.Width < 11.0, "Width is too big!");
        }

        [TestMethod]
        public void TestRenderTalkWithSubTalksOfWhichOneFailsToRender()
        {
            RenderIndicoTalk tr = new RenderIndicoTalk();
            RenderAUri ruri = new RenderAUri()
            {
                XHeight = 20.0,
                XWidth = 30.0
            };
            ruri.StringsToFailOne.Add("http://www.forkitover.com");

            t_TestingLibrary.Utilities.AddPart(ruri);
            t_TestingLibrary.Utilities.AddPart(this);
            t_TestingLibrary.Utilities.Compose(tr);

            Talk tlk = CreateNullTalkWithSubTalks();
            tlk.SubTalks[0].SlideURL = "http://www.forkitover.com";
            var result = tr.Render(tlk);
            result.Wait();
        }

        [TestMethod]
        public void TestNullTalkRender()
        {
            t_TestingLibrary.Utilities.AddPart(this);
            RenderIndicoTalk tr = new RenderIndicoTalk();
            t_TestingLibrary.Utilities.Compose(tr);

            Talk tlk = CreateSimpleTalk();
            var result = tr.Render(tlk);
            Assert.IsNotNull(result, "Expected a decent future!");
            Assert.IsNull(result.Result, "Expected a null result from the actual rendering!");
        }

        [TestMethod]
        public void TestMetadata()
        {
            t_TestingLibrary.Utilities.AddPart(new RenderIndicoTalk());
            t_TestingLibrary.Utilities.AddPart(new RenderAUri());
            t_TestingLibrary.Utilities.Compose(this);

            Talk tlk = CreateSimpleTalk();
            var result = MyRender.Render(tlk);
            Assert.IsNotNull(result, "Expected a decent result!");
            Assert.AreEqual(1, result.SGNodeList.Count, "Expecting only a single guy to come back from rendering a single talk");
        }

        [TestMethod]
        public void TestTalkIsCU()
        {
            t_TestingLibrary.Utilities.AddPart(new RenderIndicoTalk());
            t_TestingLibrary.Utilities.AddPart(new RenderAUri());
            t_TestingLibrary.Utilities.Compose(this);

            Talk tlk = CreateSimpleTalk();
            var result = MyRender.Render(tlk);
            Assert.IsTrue(result.IsCompositionUnit, "Expected the result to be a compositional unit!");
        }

#pragma warning disable 0414
        [Export("HttpAgentString")]
        private string httpAgent = "RenderIndicoTalk Test (DeepTalk)";
#pragma warning restore 0414

        [TestMethod]
        public void TestNoHEADERAllowedSite()
        {
            RenderIndicoTalk tr = new RenderIndicoTalk();
            t_TestingLibrary.Utilities.AddPart(tr);
            t_TestingLibrary.Utilities.AddPart(new RenderAUri());
            t_TestingLibrary.Utilities.Compose(this);

            Talk tlk = CreateSimpleTalk();
            tlk.SlideURL = "http://indico.ifca.es/indico/getFile.py/access?contribId=0&amp;sessionId=0&amp;resId=0&amp;materialId=slides&amp;confId=225";

            var result = MyRender.Render(tlk);

            ///
            /// And see if the date shows up!
            /// 

            Assert.IsNotNull(result.CompositionInfo.MetaData, "Expected teh meta-data value to not be null!");
        }
    }
}
